package fri.patterns.interpreter.parsergenerator.examples;

import fri.patterns.interpreter.parsergenerator.Parser;
import fri.patterns.interpreter.parsergenerator.Token;
import fri.patterns.interpreter.parsergenerator.builder.SerializedParser;
import fri.patterns.interpreter.parsergenerator.semantics.ReflectSemantic;

/**
 * Calculator for arithmetic expressions, showing the elegance of ReflectSemantic.
 * <p>
 * Syntax: java fri.patterns.interpreter.parsergenerator.examples.Calculator '(4+2.3) *(2 - -6) + 3*2'
 *
 * @author Fritz Ritzberger
 */

public class Calculator extends ReflectSemantic
{
    private static String[][] rules = { // arithmetic sample
        { "EXPRESSION", "TERM" },
        { "EXPRESSION", "EXPRESSION", "'+'", "TERM" },
        { "EXPRESSION", "EXPRESSION", "'-'", "TERM" },
        { "TERM", "FACTOR", },
        { "TERM", "TERM", "'*'", "FACTOR" },
        { "TERM", "TERM", "'/'", "FACTOR" },
        { "FACTOR", "`number`", },
        { "FACTOR", "'-'", "FACTOR" }, // need LALRParserTables instead of SLRParserTables because of this rule
        { "FACTOR", "'('", "EXPRESSION", "')'" },
        { Token.IGNORED, "`whitespaces`" },
    };

    public Object EXPRESSION(Object TERM)
    {
        return TERM; // do not really need this method as ReflectSemantic.fallback() does this
    }

    public Object EXPRESSION(Object EXPRESSION, Object operator, Object TERM)
    {
        if (operator.equals("+"))
            return new Double(((Double) EXPRESSION).doubleValue() + ((Double) TERM).doubleValue());
        return new Double(((Double) EXPRESSION).doubleValue() - ((Double) TERM).doubleValue());
    }

    public Object TERM(Object FACTOR)
    {
        return FACTOR; // do not really need this method as ReflectSemantic.fallback() does this
    }

    public Object TERM(Object TERM, Object operator, Object FACTOR)
    {
        if (operator.equals("*"))
            return new Double(((Double) TERM).doubleValue() * ((Double) FACTOR).doubleValue());
        return new Double(((Double) TERM).doubleValue() / ((Double) FACTOR).doubleValue());
    }

    public Object FACTOR(Object number)
    {
        return Double.valueOf((String) number);
    }

    public Object FACTOR(Object minus, Object FACTOR)
    {
        return new Double(-((Double) FACTOR).doubleValue());
    }

    public Object FACTOR(Object leftParenthesis, Object EXPRESSION, Object rightParenthesis)
    {
        return EXPRESSION;
    }

    /** SYNTAX: java fri.patterns.interpreter.parsergenerator.examples.Calculator '(4+2.3) *(2 - -6) + 3*2' ... 56.4. */
    public static void main(String[] args)
            throws Exception
    {
        if (args.length <= 0)
        {
            System.err.println("SYNTAX: java " + Calculator.class.getName() + " \"(4+2.3) *(2 - -6) + 3*2\"");
            System.exit(1);
        }

        String input = args[0];
        for (int i = 1; i < args.length; i++)
            input = input + " " + args[i];

        System.err.println("Calculating input >" + input + "<");

        Parser parser = new SerializedParser().get(rules, "Calculator");
        boolean ok = parser.parse(input, new Calculator());
        System.err.println("Parse return " + ok + ", result: " + parser.getResult());

        /* Variant without SerializedParser:
        SyntaxSeparation separation = new SyntaxSeparation(new Syntax(rules));	// takes away IGNORED
        LexerBuilder builder = new LexerBuilder(separation.getLexerSyntax(), separation.getIgnoredSymbols());
        Lexer lexer = builder.getLexer(input);
        ParserTables parserTables = new LALRParserTables(separation.getParserSyntax());
        Parser parser = new Parser(parserTables);
        boolean ok = parser.parse(lexer, new Calculator());
        System.err.println("Parse return "+ok+", result: "+parser.getResult());
         */
    }

}
